﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using LitJson;

namespace Marx
{
    public class ConfigSingle<T, T1> where T : ConfigSingle<T, T1>, new()
    where T1 : class, IConfigObject, new()
    {
        private static T instance_;
        private string clsName;
        public static T Instance
        {
            get
            {
                return instance_;
            }
        }

        public ConfigSingle()
        {
            Debug.Assert(instance_ == null);
        }

        protected virtual void Init(T1[] array)
        {

        }

        protected virtual void InitSingle(T1 template)
        {

        }

        public static void Load(string content, bool isArray, string name)
        {
            Debug.Assert(instance_ == null);
            Type t1 = typeof(T1);
            ///
            ///！！！！ILRuntime 未实现 MakeGenericMethod 方法
            ///
            //MethodInfo methodInfo = t1.GetMethod("Load");
            //if(methodInfo == null)
            //{
            //    methodInfo = t1.BaseType.GetMethod("Load");
            //}
            //methodInfo.MakeGenericMethod(typeof(T1));
            //object o = methodInfo.Invoke(null, new JsonData[] { data });
            instance_ = new T();
            instance_.clsName = name;
            var data = JsonMapper.ToObject(content);
            if (isArray)
            {
                var o = JsonDataUtils.Load<T1>(data);
                instance_.Init(o);
            }
            else
            {
                var o = JsonDataUtils.LoadSingle<T1>(data);
                instance_.InitSingle(o);
            }
        }

        public static void Load()
        {
            var t = typeof(T1);
            string name = t.BaseType == typeof(Object) ? t.Name : t.BaseType.Name;
            ConfigLoader.Instance.LoadHook(name, Load);
        }
    }

    public class ConfigSingleExtend<T, T1> where T : ConfigSingleExtend<T, T1>, new()
        where T1 : class, IConfigObject, new()
    {
        private static T instance_;
        public static T Instance
        {
            get
            {
                return instance_;
            }
        }

        private Dictionary<int, T1> items_;
        private string clsName;
        public ConfigSingleExtend()
        {
            Debug.Assert(instance_ == null);
        }

        protected virtual void Init(T1[] array)
        {
            items_ = new Dictionary<int, T1>();
            foreach (var item in array)
            {
                int key = GetKey(item);
                if (items_.ContainsKey(key))
                {
                    throw new Exception(string.Format("{0} is already in {1}", key, clsName));
                }
                items_.Add(key, item);
            }
            OnInit(array);
        }

        protected virtual void OnInit(T1[] array)
        {
        }

        protected virtual int GetKey(T1 item)
        {
            throw new NotImplementedException();
        }

        public T1 GetTemplate(int key)
        {
            T1 val;
            if (items_.TryGetValue(key, out val))
            {
                return val;
            }
            return null;
        }

        public static void Load(string content, bool isArray, string name)
        {
            Debug.Assert(instance_ == null);
            Type t1 = typeof(T1);
            ///
            ///！！！！ILRuntime 未实现 MakeGenericMethod 方法
            ///
            //MethodInfo methodInfo = t1.GetMethod("Load");
            //if(methodInfo == null)
            //{
            //    methodInfo = t1.BaseType.GetMethod("Load");
            //}
            //methodInfo.MakeGenericMethod(typeof(T1));
            //object o = methodInfo.Invoke(null, new JsonData[] { data });

            var data = JsonMapper.ToObject(content);
            instance_ = new T();
            instance_.clsName = name;
            if (isArray)
            {
                var o = JsonDataUtils.Load<T1>(data);
                instance_.Init(o);
            }
            else
            {
                throw new Exception("none array template should use ConfigSingle");
            }
        }

        public static void Load()
        {
            var t = typeof(T1);
            string name = t.BaseType == typeof(Object) ? t.Name : t.BaseType.Name;
            ConfigLoader.Instance.LoadHook(name, Load);
        }
    }
}